/*
 * Copyright © 2004-2014 chenYuan. All rights reserved.
 * @Website:wwww.jspx.net
 * @Mail:39793751@qq.com
 * @author: chenYuan , 陈原
 * @License: Jspx.net Framework Code is open source (LGPL)，Jspx.net Framework 使用LGPL 开源授权协议发布。
 * @jvm:jdk1.6+  x86/amd64
 *
 */
package com.jspx.txweb.dispatcher;

import com.jspx.boot.JspxNetApplication;
import com.jspx.boot.sign.HttpStatusType;
import com.jspx.json.JSONObject;
import com.jspx.txweb.InterceptorUrl;
import com.jspx.txweb.dispatcher.handle.ActionHandle;
import com.jspx.txweb.dispatcher.handle.MarkdownHandle;
import com.jspx.txweb.dispatcher.handle.RocHandle;
import com.jspx.txweb.dispatcher.handle.RsaRocHandle;
import com.jspx.txweb.evasive.EvasiveManager;
import com.jspx.txweb.util.TXWebUtil;
import com.jspx.txweb.WebConfigManager;
import com.jspx.txweb.config.TXWebConfigManager;
import com.jspx.utils.*;
import com.jspx.boot.environment.Environment;
import com.jspx.boot.environment.EnvironmentTemplate;
import com.jspx.boot.EnvFactory;
import com.jspx.sioc.BeanFactory;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.UnsupportedEncodingException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Created by IntelliJ IDEA.
 * User: chenYuan
 * Date: 2008-3-20
 * Time: 1:13:07
 * com.jspx.txweb.dispatcher.DispatcherSupport
 * DispatcherInterceptor
 * 转发器，转交action动作
 */
public class Dispatcher {
    final private static Logger log = LoggerFactory.getLogger(Dispatcher.class);
    private static final EnvironmentTemplate envTemplate = EnvFactory.getEnvironmentTemplate();
    private static final ThreadLocal<Dispatcher> instance = new ThreadLocal<Dispatcher>();
    private WebConfigManager webConfigManager = TXWebConfigManager.getInstance();
    private BeanFactory beanFactory = EnvFactory.getBeanFactory();
    final private static Map<String, WebHandle> handleList = new HashMap<String, WebHandle>(8);

    //根路径
    private static String realPath;

    //使用ThreadLocal能达到线程安全到效果
    static private boolean useThreadLocal;
    //使用回避拦截功能
    static private boolean useEvasive;

    //转发次数
    private static EvasiveManager evasiveManager = null;
    private static String encode;
    private static String markdownSuffix = "md";
    private static String filterSuffix = "jhtml";
    private static String XFrameOptions = "SAMEORIGIN";


    private Dispatcher() {
        init();
    }

    public static String getMarkdownSuffix() {
        return markdownSuffix;
    }

    public static String getEncode() {
        return encode;
    }

    public static Dispatcher getInstance() {
        if (!useThreadLocal) return new Dispatcher();
        Dispatcher du = Dispatcher.instance.get();
        if (du == null) {
            Dispatcher.instance.set(new Dispatcher());
        }
        return Dispatcher.instance.get();
    }

    public void setInstance(Dispatcher dispatcher) {
        Dispatcher.instance.set(dispatcher);
    }

    /**
     * 主要是防止关闭异常
     */
    public void init() {
        markdownSuffix = envTemplate.getString(Environment.markdownSuffix, "md");
        filterSuffix = envTemplate.getString(Environment.filterSuffix);
        encode = envTemplate.getString(Environment.encode, Environment.defaultEncode);
        useThreadLocal = envTemplate.getBoolean(Environment.useThreadLocal);
        useEvasive = envTemplate.getBoolean(Environment.useEvasive);
        XFrameOptions = envTemplate.getString(Environment.XFrameOptions,"SAMEORIGIN");

        if (useEvasive) evasiveManager = EvasiveManager.getInstance();
        //-----------------------------------------------
        handleList.put(RocHandle.name, new RocHandle());
        handleList.put(RsaRocHandle.name, new RsaRocHandle());
        handleList.put(ActionHandle.name, new ActionHandle());
        handleList.put(MarkdownHandle.name, new MarkdownHandle());
    }

    /**
     * 主要是防止关闭异常
     */
    static public void shutdown() {
        instance.set(null);
        instance.remove();
        handleList.clear();
    }

    public static String getRealPath() {
        return realPath;
    }

    public static void setRealPath(String realPath) {
        Dispatcher.realPath = realPath;
    }


    public static String getFilterSuffix()
    {
        return filterSuffix;
    }
    /**
     * @param request  请求
     * @param response 应答
     */
    void wrapRequest(HttpServletRequest request, HttpServletResponse response) {
        try {
            request.setCharacterEncoding(Dispatcher.getEncode());
            response.setCharacterEncoding(Dispatcher.getEncode());
            response.setHeader("X-Frame-Options",XFrameOptions);
        } catch (UnsupportedEncodingException e) {
            TXWebUtil.errorPrint("系统编码错误",response,403);
            log.debug("系统编码错误",e);
            return;
        }

        if (handleList.isEmpty()) {
            TXWebUtil.errorPrint("系统在启动中,请稍后", response,403);
            return;
        }

        //防刷功能 begin
        if (useEvasive &&JspxNetApplication.checkRun()&& evasiveManager.execute(request, response)) return;
        //防刷功能 end

        // 正常到执行
        String urlName = URLUtil.getFileName(request.getRequestURI());
        String namespace = TXWebUtil.getNamespace(request.getServletPath());
        List<String> pageInterceptors = webConfigManager.getPageDefaultInterceptors(namespace);
        if (pageInterceptors != null)
            for (String name : pageInterceptors) {
                InterceptorUrl dispatcherSupport = (InterceptorUrl) beanFactory.getBean(name, namespace);
                if (dispatcherSupport != null) {
                    if (!dispatcherSupport.dispatcherBefore(request, response)) return;
                }
            }

        String requestedWith = request.getHeader("X-Requested-With");
        if (URLUtil.getFileType(request.getRequestURI()).equalsIgnoreCase(markdownSuffix)) {
            try {
                handleList.get(markdownSuffix).doing(request, response);
            } catch (Exception e) {
                log.info(namespace + "/" + urlName, e);
                if (envTemplate.getBoolean(Environment.logJspxDebug)) {
                    TXWebUtil.errorPrint(e.getMessage(), response, HttpStatusType.HTTP_status_405);
                    return;
                }
            }
        } else {
            if (requestedWith == null) requestedWith = StringUtil.empty;
            requestedWith = requestedWith.toLowerCase();
            if (requestedWith.contains(Environment.rocSecret)) {
                try {
                    handleList.get(RsaRocHandle.name).doing(request, response);
                } catch (Exception e) {
                    log.error(namespace + "/" + urlName, e);
                    JSONObject errorResultJson = TXWebUtil.createRocErrorInfo(urlName,-320021,"Server error.服务器错误");
                    if (envTemplate.getBoolean(Environment.logJspxDebug)) {
                        JSONObject errorJson = errorResultJson.getJSONObject(Environment.id_error);
                        errorJson.put("exception", e.getLocalizedMessage());
                    }
                    TXWebUtil.print(errorResultJson.toString(), TXWebUtil.jsonType, response,HttpStatusType.HTTP_status_405);
                    return;
                }

            } else if (requestedWith.contains(RocHandle.name)) {
                try {
                    handleList.get(RocHandle.name).doing(request, response);
                } catch (Exception e) {
                    log.error(namespace + "/" + urlName, e);
                    JSONObject errorResultJson = TXWebUtil.createRocErrorInfo(urlName,-320022,"Server error.服务器错误");
                    if (envTemplate.getBoolean(Environment.logJspxDebug)) {
                        JSONObject errorJson = errorResultJson.getJSONObject(Environment.id_error);
                        errorJson.put("exception", e.getMessage());
                    }
                    TXWebUtil.print(errorResultJson.toString(), TXWebUtil.jsonType, response,HttpStatusType.HTTP_status_405);
                    return;
                }
            } else {
                try {
                    handleList.get(ActionHandle.name).doing(request, response);
                } catch (Exception e) {
                    e.printStackTrace();
                    log.error(namespace + "/" + urlName, e);
                    if (envTemplate.getBoolean(Environment.logJspxDebug)) {
                        TXWebUtil.errorPrint(e.getLocalizedMessage(), response,HttpStatusType.HTTP_status_405);
                        return;
                    }
                }
            }
        }

        if (pageInterceptors != null) {
            for (String pageName : pageInterceptors) {
                InterceptorUrl dispatcherSupport = (InterceptorUrl) beanFactory.getBean(pageName, namespace);
                if (dispatcherSupport != null) dispatcherSupport.dispatcherAfter(request, response);
            }
        }
    }

}